/*
 * Copyright (c) 2010 MoSync AB
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <mastring.h>
#include <mawstring.h>

#include "System.h"

using namespace MAUI;

namespace MAInterpreter
{

System* System::_instance = NULL;

System* Sys()
{
	return System::instance();
}

System::System()
{
}

System::~System()
{
	freeFontTable();
}

System* System::instance()
{
	if (System::_instance)
	{
		return System::_instance;
	}
	else
	{
		return System::_instance = new System();
	}
}

//
// Call to free singleton instance.
//
void System::releaseInstance()
{
	if (System::_instance)
	{
		delete System::_instance;
		System::_instance = NULL;
	}
}

int System::getScreenWidth()
{
	MAExtent screenSize = maGetScrSize();
	return EXTENT_X(screenSize);
}

int System::getScreenHeight()
{
	MAExtent screenSize = maGetScrSize();
	return EXTENT_Y(screenSize);
}

/**
 * This is how you bind font names:
 *  Sys()->addFont("Arial20BoldBlack", ARIAL20BOLDBLACK);
 *  Sys()->addFont("Arial32BoldBlack", ARIAL32BOLDBLACK);
 *  Sys()->addFont("Arial20BoldWhite", ARIAL20BOLDWHITE);
 *  Sys()->addFont("Arial32BoldWhite", ARIAL32BOLDBWHITE);
 *
 * Then in Lua, you can call:
 *  Screen.drawText("Hello World", 10, 10, "Arial32BoldWhite")
 */
void System::addFont(const char* fontName, MAHandle fontData)
{
	fonts.insert(fontName, new Font(fontData));
}

Font* System::getFont(const char* fontName)
{
	return fonts[fontName];
}

void System::freeFontTable()
{
    for (HashMap<String, Font*>::Iterator current = fonts.begin();
         current != fonts.end();
         current++)
    {
        delete(current->second);
    }

    fonts.clear();
}

/**
 * Helper method that reads a text string from resource file.
 * It is the responsibility of the caller of this method to
 * free the returned string with the free() function.
 * @return NULL if failing to load the text string.
 */
char* System::loadTextResource(MAHandle data)
{
	// Get size of data.
    int size = maGetDataSize(data);

    // Allocate space for text plus zero termination character.
    char* text = (char*) malloc(size + 1);
    if (NULL == text)
    {
    	return NULL;
    }

    // Read data.
    maReadData(data, text, 0, size);

    // Zero terminate string.
    text[size] = 0;

    return text;
}

/**
 * Convert a char string to a wchar string.
 * It is the responsibility of the caller to deallocate the
 * returned string.
 */
wchar* System::charToWideCharString(const char* str)
{
	if (NULL == str)
	{
		return NULL;
	}

	// Allocate result string.
	int length = strlen(str);
	wchar* wstr = (wchar*) malloc((1 + length) * sizeof(wchar));
	if (NULL == wstr)
	{
		return NULL;
	}

	// Copy string.
	int i;
	for (i = 0; i < length; ++i)
	{
		wstr[i] = str[i];
	}

	// Zero terminate string.
	wstr[i] = 0;

	return wstr;
}

/**
 * Convert a wchar string to a char string.
 * It is the responsibility of the caller to deallocate the
 * returned string.
 * Conversion only supports basic 256 char set.
 */
char* System::wideCharToCharString(const wchar* wstr)
{
	if (NULL == wstr)
	{
		return NULL;
	}

	// Allocate result string.
	int length = wcslen(wstr);
	char* str = (char*) malloc((1 + length) * sizeof(char));
	if (NULL == str)
	{
		return NULL;
	}

	// Copy string.
	int i;
	for (i = 0; i < length; ++i)
	{
		// Brute force conversion!
		str[i] = (char) wstr[i];
	}

	// Zero terminate string.
	str[i] = 0;

	return str;
}

/**
 * Helper function that writes a string to a store.
 * @return >0 on success, <0 on error.
 */
int System::writeStringToStore(const char* storeName, const char* data)
{
	// Copy string data to handle.
	MAHandle dataHandle = maCreatePlaceholder();
	int dataLength = strlen(data);
	int result = maCreateData(dataHandle, dataLength);
	if (RES_OK != result)
	{
		// Not enough memory.
		return -1;
	}

	// Write data.
	maWriteData(dataHandle, data, 0, dataLength);

	// Open the store.
	MAHandle store = maOpenStore(storeName, MAS_CREATE_IF_NECESSARY);
	if (store < 0)
	{
		// Store could not be opened.
		maDestroyObject(dataHandle);
		return -1;
	}

	// Write data to store.
	result = maWriteStore(store, dataHandle);

	// Close the store.
	maCloseStore(store, 0);

	// Delete temporary data object.
	maDestroyObject(dataHandle);

	// Return the result.
	return result > 0 ? 1 : -1;
}

/**
 * Helper function that reads a string to a store.
 * @return Pointer to string on success, NULL on error.
 */
char* System::readStringFromStore(const char* storeName)
{
	MAHandle store = maOpenStore(storeName, 0);
	if (store < 0)
	{
		// Could not open store.
		return NULL;
	}

	// Read data from the store.
	MAHandle dataHandle = maCreatePlaceholder();
	int result = maReadStore(store, dataHandle);
	if (RES_OK != result)
	{
		// Could not read from store.
		maDestroyObject(dataHandle);
		return NULL;
	}

	// Close the store.
	maCloseStore(store, 0);

	// Copy string data to buffer.
	int size = maGetDataSize(dataHandle);
	char* data = (char*) malloc(size + 1);
	if (NULL == data)
	{
		// Out of memory.
		maDestroyObject(dataHandle);
		return NULL;
	}
	maReadData(dataHandle, data, 0, size);
	data[size] = '\0';

	// Delete temporary data object.
	maDestroyObject(dataHandle);

	// Success.
	return data;
}

}

